﻿/*****************************************************************************
 * Hyldahl.Services.TaskProcessing                 Created by: MSH 2008.07.22
 * --------------------------------------------------------------------------
 * FileName: TaskProcessorPluginManager.cs
 * --------------------------------------------------------------------------
 * Copyright 2009 Martin Sixhøj Hyldahl
 *****************************************************************************/

using System;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;

namespace Hyldahl.Services.TaskProcessing
{
    public class TaskProcessorPluginManager
    {
        /*****************************************************
         * FIELDS
         *****************************************************/
        private TaskProcessingContext context;
        private Dictionary<string, TaskProcessor> taskProcessorPlugins;

        /*****************************************************
         * CONTRUCTOR
         *****************************************************/

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskProcessorPluginManager"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        public TaskProcessorPluginManager(TaskProcessingContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            
            this.context = context;
        }

        /*****************************************************
         * METHODS
         *****************************************************/

        /// <summary>
        /// Gets the task processor.
        /// </summary>
        /// <param name="taskType">Type of the task.</param>
        /// <returns></returns>
        public TaskProcessor GetTaskProcessor(string taskType)
        {
            EnsureLoadTaskProcessorPlugins();

            TaskProcessor taskProcessor = null;

            if (taskProcessorPlugins.TryGetValue(taskType.ToLower(), out taskProcessor))
                return taskProcessor;
            else
                return null;
        }

        /// <summary>
        /// Ensures the load task processor plugins.
        /// </summary>
        private void EnsureLoadTaskProcessorPlugins()
        {
            lock (this)
            {
                if (this.taskProcessorPlugins == null)
                    LoadTaskProcessorPlugins();
            }
        }

        /// <summary>
        /// Loads the task processor plugins.
        /// </summary>
        private void LoadTaskProcessorPlugins()
        {
            Trace.TraceInformation("Loading task processor plugins.");

            this.taskProcessorPlugins = new Dictionary<string, TaskProcessor>();

            string pluginDirectoryPath = AppDomain.CurrentDomain.BaseDirectory;

            DirectoryInfo pluginDirectory = new DirectoryInfo(pluginDirectoryPath);

            FileInfo[] assemblyFiles = pluginDirectory.GetFiles("*.dll");

            Trace.TraceInformation("{0} dll files found.", assemblyFiles.Length);

            foreach(FileInfo f in assemblyFiles)
            {
                try
                {
                    Trace.TraceInformation("Loading file: {0}", f.Name);

                    Assembly asm = Assembly.LoadFile(f.FullName);

                    Type[] types = asm.GetTypes();

                    Trace.TraceInformation("{0} types found in {1}.", types.Length, f.Name);

                    foreach (Type t in types)
                    {
                        if (!t.IsClass)
                            continue;

                        if (!t.IsVisible)
                            continue;

                        if (t.IsAbstract)
                            continue;

                        if (!t.IsSubclassOf(typeof(TaskProcessor)))
                            continue;

                        try
                        {
                            Trace.TraceInformation("Creating type: {0}", t.FullName);

                            TaskProcessor taskProcessor = Activator.CreateInstance(t) as TaskProcessor;

                            if (!taskProcessorPlugins.ContainsKey(taskProcessor.TaskType.ToLower()))
                                taskProcessorPlugins.Add(taskProcessor.TaskType.ToLower(), taskProcessor);
                            else
                                Trace.TraceWarning("Task processor {1} could not be added. A task processor for the task type {0} already is loaded.", taskProcessor.TaskType, taskProcessor.GetType().FullName);
                        }
                        catch (Exception ex)
                        {
                            Trace.TraceError("Could not create instance of type {0} : {1}", t.FullName, ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError("File {0} could not be loaded : {1}", f.FullName, ex.Message);
                }

                Trace.TraceInformation("{0} task processors loaded.", taskProcessorPlugins.Count);
            }
        }

        /*****************************************************
         * PROPERTIES
         *****************************************************/

        /// <summary>
        /// Gets the task processors.
        /// </summary>
        /// <value>The task processors.</value>
        public List<TaskProcessor> TaskProcessors
        {
            get
            {
                EnsureLoadTaskProcessorPlugins();

                return new List<TaskProcessor>(taskProcessorPlugins.Values);
            }
        }

    }
}
